
YAHOO.namespace('springmole');

(function () {
	
	/**
	 * Constructor for Connection panel.
	 * Panel which render a tree view to represent a database and manage all events
	 * on click and right click.
	 * @param {Object} el
	 * @param {Object} userConfig
	 */
	YAHOO.springmole.ConnectionPanel = function (el, userConfig) {
		YAHOO.springmole.ConnectionPanel.superclass.constructor.call(this, el, userConfig);
	};
	

	var Cookie = YAHOO.util.Cookie,
		Dom = YAHOO.util.Dom,		
		HttpManager = YAHOO.springmole.HttpManager,
	
		TREEVIEW_CONTAINER_ID = 'connection_tree_container_id',
		TREEVIEW_ID = 'connection_tree_id',
		TREEVIEW_CONTEXTMENU_ID = 'connection_tree_menu_id',
		
		CONNECTION_COOKIE_NAME_PREFIX = 'SpringMole_Connection-',
		
		CONNECTION_NODE_TYPE = 'connection_node_type',
		SCHEMA_NODE_TYPE = 'schema_node_type',
		TABLE_NODE_TYPE = 'table_node_type',
		
		FORM_NAME = 'dbConnection',
		FORM_ACTION = {
			connection: 'openconnection.spy',
			schema: 'openschema.spy',
			table: 'opentable.spy',
			tableData: 'opentabledata.spy'
		},
		
		/**
		 * Refer the last selected Node in the tree view.
		 * Note: right click event also update the selected Node
		 */
		oCurrentTextNode = null,
		
		oTreeView = null,
		
		oConnectionDialog = function () {},
				
		/**
		 * Database connection informations.
		 * There is one created for each ConnectionNodeData object and is 
		 * referenced by all it's child.
		 */
		Connection = function () {
			return {
				key: new Date().getTime(),
				url: 'jdbc:postgresql://localhost/test',
				userName: 'postgres',
				password: 'postgres'
			};
		},
		
		/**
		 * Object added in each connection Node using Node.data property
		 */
		ConnectionNodeData,
		
		/**
		 * Object added in each schema Node using Node.data property
		 */
		SchemaNodeData,
		
		/**
		 * Object added in each table Node using Node.data property
		 */
		TableNodeData;
		
			
	oConnectionDialog = new YAHOO.widget.Dialog('connection_dialog_id', {
		width : '300px',
		fixedcenter : true,
		visible : false,
		constraintoviewport : true,
		zIndex : 1000,
		buttons : [{
			text : "Submit",
			isDefault : true,
			handler : function () {
				this.submit();
			}
		}, {
			text : "Cancel",
			handler : function () {
				this.cancel();
			}
		}]
	});
	oConnectionDialog.render(document.body);
	
	
    function deleteConnection() {
        oTreeView.removeNode(oCurrentTextNode);
        oTreeView.draw();
    }
    
    
    function openQueryPanel() {
        if (!YAHOO.springmole.SpringMole.selectPanel('querypanel_')) {
            var queryPanel = new YAHOO.springmole.QueryPanel('querypanel_', {
                draggable: true,
                close: true,
                underlay: 'none',
                xy: [500, 100],
                connection: oCurrentTextNode.data.connection
            });
            queryPanel.render(document.body);
            YAHOO.springmole.SpringMole.addPanel(queryPanel);
        }
    }

    
	/**
	 * 
	 * @param p_oConnection
	 */	
	function createConnectionFormElement(p_oConnection) {
		var formElement = new YAHOO.springmole.FormElement();

		formElement.addInput('url', 'text', p_oConnection.url);
		formElement.addInput('userName', 'text', p_oConnection.userName);
		formElement.addInput('password', 'text', p_oConnection.password);
		formElement.addInput('key', 'hidden', p_oConnection.key);

		return formElement;
	}
	
	
	TableNodeData = function (p_oTableElement) {
        var tableName = p_oTableElement.attributes.getNamedItem('name').value,
        	itemdata = [];
        
        return {
            type: TABLE_NODE_TYPE,
            itemdata: itemdata,
            label: tableName,
            tableName: tableName,
            tableElement: p_oTableElement
        };
    };	

    
	function openSchemaNode(resultDataElement, schemaNode) {
    	var tableContainerNode,
    		viewContainerNode,
    		tableList,
    		cnt,
    		tableNode;
    	
        tableContainerNode = new YAHOO.widget.TextNode('Tables', schemaNode, true);
        viewContainerNode = new YAHOO.widget.TextNode('Views', schemaNode, false);
        
        tableList = resultDataElement.getElementsByTagName('TableList')[0];
        for (cnt = 0; cnt < tableList.childNodes.length; cnt++) {
            tableNode = new YAHOO.widget.TextNode(new TableNodeData(tableList.childNodes[cnt]), tableContainerNode, false);
            tableNode.isLeaf = true;
        }
    }	
	
	
	SchemaNodeData = function (p_sSchemaName) {
        var label = p_sSchemaName,
        	itemdata = [];
        
        function load(node, onCompleteCallback) {
            var callback,
            	formElement; 

            formElement = createConnectionFormElement(node.parent.parent.data.connection);
            YAHOO.util.Connect.setForm(formElement.buildForm(FORM_NAME, FORM_ACTION.schema).get('element'));
            
            callback = HttpManager.createYUIConnectCallBack({
                success: function (response, resultDataElement) {
                    openSchemaNode(resultDataElement, response.argument.node);
                    response.argument.onCompleteCallback();
                },
                error: function (response) {
                    alert('error');
                    response.argument.onCompleteCallback();
                },
                failure: function (response) {
                    alert('failure');
                    response.argument.onCompleteCallback();
                },
                argument: {
                	node: node, 
                	onCompleteCallback: onCompleteCallback
                }
            });
            
            YAHOO.util.Connect.asyncRequest('POST', FORM_ACTION.schema, callback, 'schemaName=' + node.label);
        }
        
        return {
            type: SCHEMA_NODE_TYPE,
            itemdata: itemdata,
            label: label,
            load: load
        };		
	};	
	
	
    /**
     * Create child "schema" node under "schemas" container node.
     *
     * @param {Object} resultDataElement
     * @param {Object} connectionNode
     */
    function openConnectionNode(resultDataElement, connectionNode) {
        var schemaContainerNode,
        	schemaElementList,
        	connection,
        	schemaName,
        	schemaNode,
        	cnt,
        	cookieCounter = 0;
        
        connection = connectionNode.data.connection;
        
        schemaContainerNode = new YAHOO.widget.TextNode('Schemas', connectionNode, true);
        
        schemaElementList = resultDataElement.getElementsByTagName('Schema');
        for (cnt = 0; cnt < schemaElementList.length; cnt++) {
            schemaName = schemaElementList[cnt].attributes.getNamedItem('name').value;
            schemaNode = new YAHOO.widget.TextNode(new SchemaNodeData(schemaName), schemaContainerNode, false);
        }
        
        connectionNode.label = connection.url;
        connectionNode.refresh();
        
        // If the connection is added in the tree for the first time
        if (connectionNode.data.isNew) {
            // Search for the next cookie name through existing cookies
            while (Cookie.get(CONNECTION_COOKIE_NAME_PREFIX + cookieCounter)) {
            	cookieCounter++;
            }
            
            // Store all connection parameters in a cookie
            Cookie.setSubs(CONNECTION_COOKIE_NAME_PREFIX + cookieCounter, connection);
        }
    }
    
    
    ConnectionNodeData = function (p_oConnection) {
		var label = p_oConnection.url,
		
			itemdata = [
				{ text: "Open query editor", onclick: { fn: openQueryPanel } },
				{ text: "Delete connection", onclick: { fn: deleteConnection } }
			];

		
		function load(node, onCompleteCallback) {	
			
	        var formElement,
	        	form;
	       
	        formElement = createConnectionFormElement(node.data.connection);
	        form = formElement.buildForm(FORM_NAME, FORM_ACTION.connection).get('element');

	        oConnectionDialog.setBody(form);
	        
	        oConnectionDialog.callback = HttpManager.createYUIConnectCallBack({
	            success: function (response, resultDataElement) {
		    		// Update the Node Connection object using the object returned from the dialog
		    		response.argument.node.data.connection = response.argument.connectionDialog.getData();
		    		
		            openConnectionNode(resultDataElement, response.argument.node);
		            
		            response.argument.onCompleteCallback();
		        },
		        error: function (response) {
		            alert('error');
		            response.argument.onCompleteCallback();
		        },
		        failure: function (response) {
		            alert('failure');
		            response.argument.onCompleteCallback();
		        },
		        argument: {
		        	node: node, 
		        	connectionDialog: oConnectionDialog,
		        	onCompleteCallback: onCompleteCallback
		        }
		    });
	        
	        oConnectionDialog.show();
		}		
		
		return {
			type: CONNECTION_NODE_TYPE,
			label: label,
			connection: p_oConnection,
			itemdata: itemdata,
			load: load,
			isNew: true
		};
	};    
    
	
    /**
     *
     */
    YAHOO.lang.extend(YAHOO.springmole.ConnectionPanel, YAHOO.springmole.SpringMolePanel, {

    	/**
    	 * @param p_oConnectionNodeData
    	 * @param p_bExpand
    	 */
        _createConnectionNode: function (p_oConnectionNodeData, p_bExpand) {
            return new YAHOO.widget.TextNode(p_oConnectionNodeData, oTreeView.getRoot(), p_bExpand);
        },
        
        
        init: function (el, userConfig) {
            YAHOO.springmole.ConnectionPanel.superclass.init.call(this, el, userConfig);
            
            this.setHeader("Connections");
            this.setBody(
            		'<div id="' + TREEVIEW_CONTAINER_ID + '">' +
            		'<div id="' + TREEVIEW_ID + '"></div>' +
            		'</div>');
            
            // Initialise a empty context menu and subscribe to "triggerContextMenu" event
            // to set a specific array of menu items before opening the menu 
            var oContextMenu = new YAHOO.widget.ContextMenu(TREEVIEW_CONTEXTMENU_ID, {
                zIndex: 1000,
                trigger: TREEVIEW_ID,
                lazyload: true,
                itemdata: []
            });
            
            // TreeView context menu event handler for the element(s) that triggered the display of the ContextMenu instance.
            // Used to set a reference with the protected variable _oCurrentTextNode to the TextNode instance that 
            // triggered the display of the ContextMenu instance.
            oContextMenu.subscribe('triggerContextMenu', function (p_oEvent, p_oMouseEvent) {
                var oTarget = this.contextEventTarget;
                
                // Get the TextNode instance that triggered the display of the ContextMenu instance.
                oCurrentTextNode = oTreeView.getNodeByElement(oTarget);
                
                if (!oCurrentTextNode) {
                    // Cancel the display of the ContextMenu instance.
                    this.cancel();
                }
                else {
                    oContextMenu.clearContent();
                    oContextMenu.addItems(oCurrentTextNode.data.itemdata);
                    oContextMenu.render(document.body);
                }
            }, this, false);
        },
        
        
        render: function (parentNode) {
            YAHOO.springmole.ConnectionPanel.superclass.render.call(this, parentNode);
            
            var connectionNodeData,
            	cookieCounter = 0;
            
            oTreeView = new YAHOO.widget.TreeView(TREEVIEW_ID);
            
            // Turn dynamic loading on for entire tree:
            oTreeView.setDynamicLoad(function (node, onCompleteCallback) {
                // The load function is implemented by every expandable node.
                // Each node type define a specific data transfer.
                if (node.data.load) {
                    node.data.load(node, onCompleteCallback);
                } else {
                    onCompleteCallback();
                }
            });
            
            oTreeView.subscribe('labelClick', function (node) {
                if (node.data.type === TABLE_NODE_TYPE) {
                
                    if (!YAHOO.springmole.SpringMole.selectPanel('tablepanel_' + node.data.tableName)) {
                        var tablePanel = new YAHOO.springmole.TablePanel('tablepanel_' + node.data.tableName, {
                            draggable: true,
                            close: true,
                            xy: [500, 100],
                            tableXmlConfig: node.data.tableElement,
                            connection: node.parent.parent.parent.parent.data.connection
                        });
                        tablePanel.render(document.body);
                        YAHOO.springmole.SpringMole.addPanel(tablePanel);
                    }
                    
                }
            });
            
            // Initialise connection tree from stored cookies         			
            while (Cookie.get(CONNECTION_COOKIE_NAME_PREFIX + cookieCounter)) {
            	connectionNodeData = new ConnectionNodeData(Cookie.getSubs(CONNECTION_COOKIE_NAME_PREFIX + cookieCounter));
            	connectionNodeData.isNew = false;
                this._createConnectionNode(connectionNodeData, false);
                cookieCounter++;
            }
            
            oTreeView.draw();
            
            return true;
        },
        
        
        createNewConnectionNode: function () {
        	this._createConnectionNode(new ConnectionNodeData(new Connection()), true);
        	
            // The new connection node is configured to be expanded,
            // so when refreshing the tree, it call the method assigned by setDynamicLoad
            oTreeView.draw();
        }
        

    });
    
	
}());
